home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / std_unix / pax / 6 < prev    next >
Encoding:
Text File  |  1989-01-07  |  32.4 KB  |  1,360 lines

  1. #! /bin/sh
  2. # This is a shell archive.  Remove anything before this line, then unpack
  3. # it by saving it into a file and typing "sh file".  To overwrite existing
  4. # files, type "sh file -c".  You can also feed this as standard input via
  5. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  6. # will see the following message at the end:
  7. #        "End of archive 6 (of 6)."
  8. # Contents:  regexp.c
  9. # Wrapped by mark@jhereg on Sat Jan  7 00:26:05 1989
  10. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  11. if test -f regexp.c -a "${1}" != "-c" ; then 
  12.   echo shar: Will not over-write existing file \"regexp.c\"
  13. else
  14. echo shar: Extracting \"regexp.c\" \(30611 characters\)
  15. sed "s/^X//" >regexp.c <<'END_OF_regexp.c'
  16. X/* $Source: /u/mark/src/pax/RCS/regexp.c,v $
  17. X *
  18. X * $Revision: 1.1 $
  19. X *
  20. X * regexp.c - regular expression matching
  21. X *
  22. X * DESCRIPTION
  23. X *
  24. X *    Underneath the reformatting and comment blocks which were added to 
  25. X *    make it consistent with the rest of the code, you will find a
  26. X *    modified version of Henry Specer's regular expression library.
  27. X *    Henry's functions were modified to provide the minimal regular
  28. X *    expression matching, as required by P1003.  Henry's code was
  29. X *    copyrighted, and copy of the copyright message and restrictions
  30. X *    are provided, verbatim, below:
  31. X *
  32. X *    Copyright (c) 1986 by University of Toronto.
  33. X *    Written by Henry Spencer.  Not derived from licensed software.
  34. X *
  35. X *    Permission is granted to anyone to use this software for any
  36. X *    purpose on any computer system, and to redistribute it freely,
  37. X *    subject to the following restrictions:
  38. X *
  39. X *    1. The author is not responsible for the consequences of use of
  40. X *         this software, no matter how awful, even if they arise
  41. X *       from defects in it.
  42. X *
  43. X *    2. The origin of this software must not be misrepresented, either
  44. X *       by explicit claim or by omission.
  45. X *
  46. X *    3. Altered versions must be plainly marked as such, and must not
  47. X *       be misrepresented as being the original software.
  48. X *
  49. X *     Beware that some of this code is subtly aware of the way operator
  50. X *     precedence is structured in regular expressions.  Serious changes in
  51. X *     regular-expression syntax might require a total rethink.
  52. X *
  53. X * AUTHORS
  54. X *
  55. X *     Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
  56. X *     Henry Spencer, University of Torronto (henry@utzoo.edu)
  57. X *
  58. X * Sponsored by The USENIX Association for public distribution. 
  59. X *
  60. X * $Log:    regexp.c,v $
  61. X * Revision 1.1  88/12/23  18:02:32  mark
  62. X * Initial revision
  63. X * 
  64. X */
  65. X
  66. X/* Headers */
  67. X
  68. X#include "pax.h"
  69. X
  70. X#ifndef lint
  71. Xstatic char    *Ident = "$Id: regexp.c,v 1.1 88/12/23 18:02:32 mark Rel $";
  72. X#endif
  73. X
  74. X
  75. X/*
  76. X * The "internal use only" fields in regexp.h are present to pass info from
  77. X * compile to execute that permits the execute phase to run lots faster on
  78. X * simple cases.  They are:
  79. X *
  80. X * regstart    char that must begin a match; '\0' if none obvious
  81. X * reganch    is the match anchored (at beginning-of-line only)?
  82. X * regmust    string (pointer into program) that match must include, or NULL
  83. X * regmlen    length of regmust string
  84. X *
  85. X * Regstart and reganch permit very fast decisions on suitable starting points
  86. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  87. X * of lines that cannot possibly match.  The regmust tests are costly enough
  88. X * that regcomp() supplies a regmust only if the r.e. contains something
  89. X * potentially expensive (at present, the only such thing detected is * or +
  90. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  91. X * supplied because the test in regexec() needs it and regcomp() is computing
  92. X * it anyway.
  93. X */
  94. X
  95. X/*
  96. X * Structure for regexp "program".  This is essentially a linear encoding
  97. X * of a nondeterministic finite-state machine (aka syntax charts or
  98. X * "railroad normal form" in parsing technology).  Each node is an opcode
  99. X * plus a "nxt" pointer, possibly plus an operand.  "Nxt" pointers of
  100. X * all nodes except BRANCH implement concatenation; a "nxt" pointer with
  101. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  102. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  103. X * opposed to a collection of them) is never concatenated with anything
  104. X * because of operator precedence.)  The operand of some types of node is
  105. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  106. X * particular, the operand of a BRANCH node is the first node of the branch.
  107. X * (NB this is *not* a tree structure:  the tail of the branch connects
  108. X * to the thing following the set of BRANCHes.)  The opcodes are:
  109. X */
  110. X
  111. X/* definition    number    opnd?    meaning */
  112. X#define    END    0        /* no    End of program. */
  113. X#define    BOL    1        /* no    Match "" at beginning of line. */
  114. X#define    EOL    2        /* no    Match "" at end of line. */
  115. X#define    ANY    3        /* no    Match any one character. */
  116. X#define    ANYOF    4        /* str    Match any character in this string. */
  117. X#define    ANYBUT    5        /* str    Match any character not in this
  118. X                 * string. */
  119. X#define    BRANCH    6        /* node    Match this alternative, or the
  120. X                 * nxt... */
  121. X#define    BACK    7        /* no    Match "", "nxt" ptr points backward. */
  122. X#define    EXACTLY    8        /* str    Match this string. */
  123. X#define    NOTHING    9        /* no    Match empty string. */
  124. X#define    STAR    10        /* node    Match this (simple) thing 0 or more
  125. X                 * times. */
  126. X#define    OPEN    20        /* no    Mark this point in input as start of
  127. X                 * #n. */
  128. X /* OPEN+1 is number 1, etc. */
  129. X#define    CLOSE    30        /* no    Analogous to OPEN. */
  130. X
  131. X/*
  132. X * Opcode notes:
  133. X *
  134. X * BRANCH    The set of branches constituting a single choice are hooked
  135. X *        together with their "nxt" pointers, since precedence prevents
  136. X *        anything being concatenated to any individual branch.  The
  137. X *        "nxt" pointer of the last BRANCH in a choice points to the
  138. X *        thing following the whole choice.  This is also where the
  139. X *        final "nxt" pointer of each individual branch points; each
  140. X *        branch starts with the operand node of a BRANCH node.
  141. X *
  142. X * BACK        Normal "nxt" pointers all implicitly point forward; BACK
  143. X *        exists to make loop structures possible.
  144. X *
  145. X * STAR        complex '*', are implemented as circular BRANCH structures 
  146. X *        using BACK.  Simple cases (one character per match) are 
  147. X *        implemented with STAR for speed and to minimize recursive 
  148. X *        plunges.
  149. X *
  150. X * OPEN,CLOSE    ...are numbered at compile time.
  151. X */
  152. X
  153. X/*
  154. X * A node is one char of opcode followed by two chars of "nxt" pointer.
  155. X * "Nxt" pointers are stored as two 8-bit pieces, high order first.  The
  156. X * value is a positive offset from the opcode of the node containing it.
  157. X * An operand, if any, simply follows the node.  (Note that much of the
  158. X * code generation knows about this implicit relationship.)
  159. X *
  160. X * Using two bytes for the "nxt" pointer is vast overkill for most things,
  161. X * but allows patterns to get big without disasters.
  162. X */
  163. X#define    OP(p)    (*(p))
  164. X#define    NEXT(p)    (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
  165. X#define    OPERAND(p)    ((p) + 3)
  166. X
  167. X/*
  168. X * Utility definitions.
  169. X */
  170. X
  171. X#define    FAIL(m)    { regerror(m); return(NULL); }
  172. X#define    ISMULT(c)    ((c) == '*')
  173. X#define    META    "^$.[()|*\\"
  174. X#ifndef CHARBITS
  175. X#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  176. X#else
  177. X#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  178. X#endif
  179. X
  180. X/*
  181. X * Flags to be passed up and down.
  182. X */
  183. X#define    HASWIDTH    01    /* Known never to match null string. */
  184. X#define    SIMPLE        02    /* Simple enough to be STAR operand. */
  185. X#define    SPSTART        04    /* Starts with * */
  186. X#define    WORST        0    /* Worst case. */
  187. X
  188. X/*
  189. X * Global work variables for regcomp().
  190. X */
  191. Xstatic char    *regparse;    /* Input-scan pointer. */
  192. Xstatic int      regnpar;    /* () count. */
  193. Xstatic char     regdummy;
  194. Xstatic char    *regcode;    /* Code-emit pointer; ®dummy = don't. */
  195. Xstatic long     regsize;    /* Code size. */
  196. X
  197. X/*
  198. X * Forward declarations for regcomp()'s friends.
  199. X */
  200. X#ifndef STATIC
  201. X#define    STATIC    static
  202. X#endif
  203. XSTATIC char    *reg();
  204. XSTATIC char    *regbranch();
  205. XSTATIC char    *regpiece();
  206. XSTATIC char    *regatom();
  207. XSTATIC char    *regnode();
  208. XSTATIC char    *regnext();
  209. XSTATIC void     regc();
  210. XSTATIC void     reginsert();
  211. XSTATIC void     regtail();
  212. XSTATIC void     regoptail();
  213. X#ifdef STRCSPN
  214. XSTATIC int      strcspn();
  215. X#endif
  216. X
  217. X/*
  218. X - regcomp - compile a regular expression into internal code
  219. X *
  220. X * We can't allocate space until we know how big the compiled form will be,
  221. X * but we can't compile it (and thus know how big it is) until we've got a
  222. X * place to put the code.  So we cheat:  we compile it twice, once with code
  223. X * generation turned off and size counting turned on, and once "for real".
  224. X * This also means that we don't allocate space until we are sure that the
  225. X * thing really will compile successfully, and we never have to move the
  226. X * code and thus invalidate pointers into it.  (Note that it has to be in
  227. X * one piece because free() must be able to free it all.)
  228. X *
  229. X * Beware that the optimization-preparation code in here knows about some
  230. X * of the structure of the compiled regexp.
  231. X */
  232. Xregexp *regcomp(exp)
  233. Xchar           *exp;
  234. X{
  235. X    register regexp *r;
  236. X    register char  *scan;
  237. X    register char  *longest;
  238. X    register int    len;
  239. X    int             flags;
  240. X    extern char    *malloc();
  241. X
  242. X    if (exp == NULL)
  243. X    FAIL("NULL argument");
  244. X
  245. X    /* First pass: determine size, legality. */
  246. X    regparse = exp;
  247. X    regnpar = 1;
  248. X    regsize = 0L;
  249. X    regcode = ®dummy;
  250. X    regc(MAGIC);
  251. X    if (reg(0, &flags) == NULL)
  252. X    return (NULL);
  253. X
  254. X    /* Small enough for pointer-storage convention? */
  255. X    if (regsize >= 32767L)    /* Probably could be 65535L. */
  256. X    FAIL("regexp too big");
  257. X
  258. X    /* Allocate space. */
  259. X    r = (regexp *) malloc(sizeof(regexp) + (unsigned) regsize);
  260. X    if (r == NULL)
  261. X    FAIL("out of space");
  262. X
  263. X    /* Second pass: emit code. */
  264. X    regparse = exp;
  265. X    regnpar = 1;
  266. X    regcode = r->program;
  267. X    regc(MAGIC);
  268. X    if (reg(0, &flags) == NULL)
  269. X    return (NULL);
  270. X
  271. X    /* Dig out information for optimizations. */
  272. X    r->regstart = '\0';        /* Worst-case defaults. */
  273. X    r->reganch = 0;
  274. X    r->regmust = NULL;
  275. X    r->regmlen = 0;
  276. X    scan = r->program + 1;    /* First BRANCH. */
  277. X    if (OP(regnext(scan)) == END) {    /* Only one top-level choice. */
  278. X    scan = OPERAND(scan);
  279. X
  280. X    /* Starting-point info. */
  281. X    if (OP(scan) == EXACTLY)
  282. X        r->regstart = *OPERAND(scan);
  283. X    else if (OP(scan) == BOL)
  284. X        r->reganch++;
  285. X
  286. X    /*
  287. X     * If there's something expensive in the r.e., find the longest
  288. X     * literal string that must appear and make it the regmust.  Resolve
  289. X     * ties in favor of later strings, since the regstart check works
  290. X     * with the beginning of the r.e. and avoiding duplication
  291. X     * strengthens checking.  Not a strong reason, but sufficient in the
  292. X     * absence of others. 
  293. X     */
  294. X    if (flags & SPSTART) {
  295. X        longest = NULL;
  296. X        len = 0;
  297. X        for (; scan != NULL; scan = regnext(scan))
  298. X        if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  299. X            longest = OPERAND(scan);
  300. X            len = strlen(OPERAND(scan));
  301. X        }
  302. X        r->regmust = longest;
  303. X        r->regmlen = len;
  304. X    }
  305. X    }
  306. X    return (r);
  307. X}
  308. X
  309. X/*
  310. X - reg - regular expression, i.e. main body or parenthesized thing
  311. X *
  312. X * Caller must absorb opening parenthesis.
  313. X *
  314. X * Combining parenthesis handling with the base level of regular expression
  315. X * is a trifle forced, but the need to tie the tails of the branches to what
  316. X * follows makes it hard to avoid.
  317. X */
  318. Xstatic char *reg(paren, flagp)
  319. Xint             paren;        /* Parenthesized? */
  320. Xint            *flagp;
  321. X{
  322. X    register char  *ret;
  323. X    register char  *br;
  324. X    register char  *ender;
  325. X    register int    parno;
  326. X    int             flags;
  327. X
  328. X    *flagp = HASWIDTH;        /* Tentatively. */
  329. X
  330. X    /* Make an OPEN node, if parenthesized. */
  331. X    if (paren) {
  332. X    if (regnpar >= NSUBEXP)
  333. X        FAIL("too many ()");
  334. X    parno = regnpar;
  335. X    regnpar++;
  336. X    ret = regnode(OPEN + parno);
  337. X    } else
  338. X    ret = NULL;
  339. X
  340. X    /* Pick up the branches, linking them together. */
  341. X    br = regbranch(&flags);
  342. X    if (br == NULL)
  343. X    return (NULL);
  344. X    if (ret != NULL)
  345. X    regtail(ret, br);    /* OPEN -> first. */
  346. X    else
  347. X    ret = br;
  348. X    if (!(flags & HASWIDTH))
  349. X    *flagp &= ~HASWIDTH;
  350. X    *flagp |= flags & SPSTART;
  351. X    while (*regparse == '|') {
  352. X    regparse++;
  353. X    br = regbranch(&flags);
  354. X    if (br == NULL)
  355. X        return (NULL);
  356. X    regtail(ret, br);    /* BRANCH -> BRANCH. */
  357. X    if (!(flags & HASWIDTH))
  358. X        *flagp &= ~HASWIDTH;
  359. X    *flagp |= flags & SPSTART;
  360. X    }
  361. X
  362. X    /* Make a closing node, and hook it on the end. */
  363. X    ender = regnode((paren) ? CLOSE + parno : END);
  364. X    regtail(ret, ender);
  365. X
  366. X    /* Hook the tails of the branches to the closing node. */
  367. X    for (br = ret; br != NULL; br = regnext(br))
  368. X    regoptail(br, ender);
  369. X
  370. X    /* Check for proper termination. */
  371. X    if (paren && *regparse++ != ')') {
  372. X    FAIL("unmatched ()");
  373. X    } else if (!paren && *regparse != '\0') {
  374. X    if (*regparse == ')') {
  375. X        FAIL("unmatched ()");
  376. X    } else
  377. X        FAIL("junk on end");/* "Can't happen". */
  378. X    /* NOTREACHED */
  379. X    }
  380. X    return (ret);
  381. X}
  382. X
  383. X/*
  384. X - regbranch - one alternative of an | operator
  385. X *
  386. X * Implements the concatenation operator.
  387. X */
  388. Xstatic char  *regbranch(flagp)
  389. Xint            *flagp;
  390. X{
  391. X    register char  *ret;
  392. X    register char  *chain;
  393. X    register char  *latest;
  394. X    int             flags;
  395. X
  396. X    *flagp = WORST;        /* Tentatively. */
  397. X
  398. X    ret = regnode(BRANCH);
  399. X    chain = NULL;
  400. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  401. X    latest = regpiece(&flags);
  402. X    if (latest == NULL)
  403. X        return (NULL);
  404. X    *flagp |= flags & HASWIDTH;
  405. X    if (chain == NULL)    /* First piece. */
  406. X        *flagp |= flags & SPSTART;
  407. X    else
  408. X        regtail(chain, latest);
  409. X    chain = latest;
  410. X    }
  411. X    if (chain == NULL)        /* Loop ran zero times. */
  412. X    regnode(NOTHING);
  413. X
  414. X    return (ret);
  415. X}
  416. X
  417. X/*
  418. X - regpiece - something followed by possible [*]
  419. X *
  420. X * Note that the branching code sequence used for * is somewhat optimized:  
  421. X * they use the same NOTHING node as both the endmarker for their branch 
  422. X * list and the body of the last branch.  It might seem that this node could 
  423. X * be dispensed with entirely, but the endmarker role is not redundant.
  424. X */
  425. Xstatic char *regpiece(flagp)
  426. Xint            *flagp;
  427. X{
  428. X    register char  *ret;
  429. X    register char   op;
  430. X    register char  *nxt;
  431. X    int             flags;
  432. X
  433. X    ret = regatom(&flags);
  434. X    if (ret == NULL)
  435. X    return (NULL);
  436. X
  437. X    op = *regparse;
  438. X    if (!ISMULT(op)) {
  439. X    *flagp = flags;
  440. X    return (ret);
  441. X    }
  442. X    if (!(flags & HASWIDTH))
  443. X    FAIL("* operand could be empty");
  444. X    *flagp = (WORST | SPSTART);
  445. X
  446. X    if (op == '*' && (flags & SIMPLE))
  447. X    reginsert(STAR, ret);
  448. X    else if (op == '*') {
  449. X    /* Emit x* as (x&|), where & means "self". */
  450. X    reginsert(BRANCH, ret);    /* Either x */
  451. X    regoptail(ret, regnode(BACK));    /* and loop */
  452. X    regoptail(ret, ret);    /* back */
  453. X    regtail(ret, regnode(BRANCH));    /* or */
  454. X    regtail(ret, regnode(NOTHING));    /* null. */
  455. X    } 
  456. X    regparse++;
  457. X    if (ISMULT(*regparse))
  458. X    FAIL("nested *");
  459. X
  460. X    return (ret);
  461. X}
  462. X
  463. X/*
  464. X - regatom - the lowest level
  465. X *
  466. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  467. X * it can turn them into a single node, which is smaller to store and
  468. X * faster to run.  Backslashed characters are exceptions, each becoming a
  469. X * separate node; the code is simpler that way and it's not worth fixing.
  470. X */
  471. Xstatic char *regatom(flagp)
  472. Xint            *flagp;
  473. X{
  474. X    register char  *ret;
  475. X    int             flags;
  476. X
  477. X    *flagp = WORST;        /* Tentatively. */
  478. X
  479. X    switch (*regparse++) {
  480. X    case '^':
  481. X    ret = regnode(BOL);
  482. X    break;
  483. X    case '$':
  484. X    ret = regnode(EOL);
  485. X    break;
  486. X    case '.':
  487. X    ret = regnode(ANY);
  488. X    *flagp |= HASWIDTH | SIMPLE;
  489. X    break;
  490. X    case '[':{
  491. X        register int    class;
  492. X        register int    classend;
  493. X
  494. X        if (*regparse == '^') {    /* Complement of range. */
  495. X        ret = regnode(ANYBUT);
  496. X        regparse++;
  497. X        } else
  498. X        ret = regnode(ANYOF);
  499. X        if (*regparse == ']' || *regparse == '-')
  500. X        regc(*regparse++);
  501. X        while (*regparse != '\0' && *regparse != ']') {
  502. X        if (*regparse == '-') {
  503. X            regparse++;
  504. X            if (*regparse == ']' || *regparse == '\0')
  505. X            regc('-');
  506. X            else {
  507. X            class = UCHARAT(regparse - 2) + 1;
  508. X            classend = UCHARAT(regparse);
  509. X            if (class > classend + 1)
  510. X                FAIL("invalid [] range");
  511. X            for (; class <= classend; class++)
  512. X                regc(class);
  513. X            regparse++;
  514. X            }
  515. X        } else
  516. X            regc(*regparse++);
  517. X        }
  518. X        regc('\0');
  519. X        if (*regparse != ']')
  520. X        FAIL("unmatched []");
  521. X        regparse++;
  522. X        *flagp |= HASWIDTH | SIMPLE;
  523. X    }
  524. X    break;
  525. X    case '(':
  526. X    ret = reg(1, &flags);
  527. X    if (ret == NULL)
  528. X        return (NULL);
  529. X    *flagp |= flags & (HASWIDTH | SPSTART);
  530. X    break;
  531. X    case '\0':
  532. X    case '|':
  533. X    case ')':
  534. X    FAIL("internal urp");    /* Supposed to be caught earlier. */
  535. X    break;
  536. X    case '*':
  537. X    FAIL("* follows nothing");
  538. X    break;
  539. X    case '\\':
  540. X    if (*regparse == '\0')
  541. X        FAIL("trailing \\");
  542. X    ret = regnode(EXACTLY);
  543. X    regc(*regparse++);
  544. X    regc('\0');
  545. X    *flagp |= HASWIDTH | SIMPLE;
  546. X    break;
  547. X    default:{
  548. X        register int    len;
  549. X        register char   ender;
  550. X
  551. X        regparse--;
  552. X        len = strcspn(regparse, META);
  553. X        if (len <= 0)
  554. X        FAIL("internal disaster");
  555. X        ender = *(regparse + len);
  556. X        if (len > 1 && ISMULT(ender))
  557. X        len--;        /* Back off clear of * operand. */
  558. X        *flagp |= HASWIDTH;
  559. X        if (len == 1)
  560. X        *flagp |= SIMPLE;
  561. X        ret = regnode(EXACTLY);
  562. X        while (len > 0) {
  563. X        regc(*regparse++);
  564. X        len--;
  565. X        }
  566. X        regc('\0');
  567. X    }
  568. X    break;
  569. X    }
  570. X
  571. X    return (ret);
  572. X}
  573. X
  574. X/*
  575. X - regnode - emit a node
  576. X */
  577. Xstatic char *regnode(op)
  578. Xchar            op;
  579. X{
  580. X    register char  *ret;
  581. X    register char  *ptr;
  582. X
  583. X    ret = regcode;
  584. X    if (ret == ®dummy) {
  585. X    regsize += 3;
  586. X    return (ret);
  587. X    }
  588. X    ptr = ret;
  589. X    *ptr++ = op;
  590. X    *ptr++ = '\0';        /* Null "nxt" pointer. */
  591. X    *ptr++ = '\0';
  592. X    regcode = ptr;
  593. X
  594. X    return (ret);
  595. X}
  596. X
  597. X/*
  598. X - regc - emit (if appropriate) a byte of code
  599. X */
  600. Xstatic void regc(b)
  601. Xchar            b;
  602. X{
  603. X    if (regcode != ®dummy)
  604. X    *regcode++ = b;
  605. X    else
  606. X    regsize++;
  607. X}
  608. X
  609. X/*
  610. X - reginsert - insert an operator in front of already-emitted operand
  611. X *
  612. X * Means relocating the operand.
  613. X */
  614. Xstatic void reginsert(op, opnd)
  615. Xchar            op;
  616. Xchar           *opnd;
  617. X{
  618. X    register char  *src;
  619. X    register char  *dst;
  620. X    register char  *place;
  621. X
  622. X    if (regcode == ®dummy) {
  623. X    regsize += 3;
  624. X    return;
  625. X    }
  626. X    src = regcode;
  627. X    regcode += 3;
  628. X    dst = regcode;
  629. X    while (src > opnd)
  630. X    *--dst = *--src;
  631. X
  632. X    place = opnd;        /* Op node, where operand used to be. */
  633. X    *place++ = op;
  634. X    *place++ = '\0';
  635. X    *place++ = '\0';
  636. X}
  637. X
  638. X/*
  639. X - regtail - set the next-pointer at the end of a node chain
  640. X */
  641. Xstatic void regtail(p, val)
  642. Xchar           *p;
  643. Xchar           *val;
  644. X{
  645. X    register char  *scan;
  646. X    register char  *temp;
  647. X    register int    offset;
  648. X
  649. X    if (p == ®dummy)
  650. X    return;
  651. X
  652. X    /* Find last node. */
  653. X    scan = p;
  654. X    for (;;) {
  655. X    temp = regnext(scan);
  656. X    if (temp == NULL)
  657. X        break;
  658. X    scan = temp;
  659. X    }
  660. X
  661. X    if (OP(scan) == BACK)
  662. X    offset = scan - val;
  663. X    else
  664. X    offset = val - scan;
  665. X    *(scan + 1) = (offset >> 8) & 0377;
  666. X    *(scan + 2) = offset & 0377;
  667. X}
  668. X
  669. X/*
  670. X - regoptail - regtail on operand of first argument; nop if operandless
  671. X */
  672. Xstatic void regoptail(p, val)
  673. Xchar           *p;
  674. Xchar           *val;
  675. X{
  676. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  677. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  678. X    return;
  679. X    regtail(OPERAND(p), val);
  680. X}
  681. X
  682. X/*
  683. X * regexec and friends
  684. X */
  685. X
  686. X/*
  687. X * Global work variables for regexec().
  688. X */
  689. Xstatic char    *reginput;    /* String-input pointer. */
  690. Xstatic char    *regbol;        /* Beginning of input, for ^ check. */
  691. Xstatic char   **regstartp;    /* Pointer to startp array. */
  692. Xstatic char   **regendp;    /* Ditto for endp. */
  693. X
  694. X/*
  695. X * Forwards.
  696. X */
  697. XSTATIC int      regtry();
  698. XSTATIC int      regmatch();
  699. XSTATIC int      regrepeat();
  700. X
  701. X#ifdef DEBUG
  702. Xint             regnarrate = 0;
  703. Xvoid            regdump();
  704. XSTATIC char    *regprop();
  705. X#endif
  706. X
  707. X/*
  708. X - regexec - match a regexp against a string
  709. X */
  710. Xint regexec(prog, string)
  711. Xregister regexp *prog;
  712. Xregister char  *string;
  713. X{
  714. X    register char  *s;
  715. X
  716. X    /* Be paranoid... */
  717. X    if (prog == NULL || string == NULL) {
  718. X    regerror("NULL parameter");
  719. X    return (0);
  720. X    }
  721. X    /* Check validity of program. */
  722. X    if (UCHARAT(prog->program) != MAGIC) {
  723. X    regerror("corrupted program");
  724. X    return (0);
  725. X    }
  726. X    /* If there is a "must appear" string, look for it. */
  727. X    if (prog->regmust != NULL) {
  728. X    s = string;
  729. X    while ((s = strchr(s, prog->regmust[0])) != NULL) {
  730. X        if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  731. X        break;        /* Found it. */
  732. X        s++;
  733. X    }
  734. X    if (s == NULL)        /* Not present. */
  735. X        return (0);
  736. X    }
  737. X    /* Mark beginning of line for ^ . */
  738. X    regbol = string;
  739. X
  740. X    /* Simplest case:  anchored match need be tried only once. */
  741. X    if (prog->reganch)
  742. X    return (regtry(prog, string));
  743. X
  744. X    /* Messy cases:  unanchored match. */
  745. X    s = string;
  746. X    if (prog->regstart != '\0')
  747. X    /* We know what char it must start with. */
  748. X    while ((s = strchr(s, prog->regstart)) != NULL) {
  749. X        if (regtry(prog, s))
  750. X        return (1);
  751. X        s++;
  752. X    }
  753. X    else
  754. X    /* We don't -- general case. */
  755. X    do {
  756. X        if (regtry(prog, s))
  757. X        return (1);
  758. X    } while (*s++ != '\0');
  759. X
  760. X    /* Failure. */
  761. X    return (0);
  762. X}
  763. X
  764. X/*
  765. X - regtry - try match at specific point
  766. X */
  767. X#ifdef __STDC__
  768. X
  769. Xstatic int regtry(regexp *prog, char *string)
  770. X
  771. X#else
  772. X
  773. Xstatic int regtry(prog, string)
  774. Xregexp         *prog;
  775. Xchar           *string;
  776. X
  777. X#endif
  778. X{
  779. X    register int    i;
  780. X    register char **sp;
  781. X    register char **ep;
  782. X
  783. X    reginput = string;
  784. X    regstartp = prog->startp;
  785. X    regendp = prog->endp;
  786. X
  787. X    sp = prog->startp;
  788. X    ep = prog->endp;
  789. X    for (i = NSUBEXP; i > 0; i--) {
  790. X    *sp++ = NULL;
  791. X    *ep++ = NULL;
  792. X    }
  793. X    if (regmatch(prog->program + 1)) {
  794. X    prog->startp[0] = string;
  795. X    prog->endp[0] = reginput;
  796. X    return (1);
  797. X    } else
  798. X    return (0);
  799. X}
  800. X
  801. X/*
  802. X - regmatch - main matching routine
  803. X *
  804. X * Conceptually the strategy is simple:  check to see whether the current
  805. X * node matches, call self recursively to see whether the rest matches,
  806. X * and then act accordingly.  In practice we make some effort to avoid
  807. X * recursion, in particular by going through "ordinary" nodes (that don't
  808. X * need to know whether the rest of the match failed) by a loop instead of
  809. X * by recursion.
  810. X */
  811. X#ifdef __STDC__
  812. X
  813. Xstatic int regmatch(char *prog)
  814. X
  815. X#else
  816. X
  817. Xstatic int regmatch(prog)
  818. Xchar           *prog;
  819. X
  820. X#endif
  821. X{
  822. X    register char  *scan;    /* Current node. */
  823. X    char           *nxt;    /* nxt node. */
  824. X
  825. X    scan = prog;
  826. X#ifdef DEBUG
  827. X    if (scan != NULL && regnarrate)
  828. X    fprintf(stderr, "%s(\n", regprop(scan));
  829. X#endif
  830. X    while (scan != NULL) {
  831. X#ifdef DEBUG
  832. X    if (regnarrate)
  833. X        fprintf(stderr, "%s...\n", regprop(scan));
  834. X#endif
  835. X    nxt = regnext(scan);
  836. X
  837. X    switch (OP(scan)) {
  838. X    case BOL:
  839. X        if (reginput != regbol)
  840. X        return (0);
  841. X        break;
  842. X    case EOL:
  843. X        if (*reginput != '\0')
  844. X        return (0);
  845. X        break;
  846. X    case ANY:
  847. X        if (*reginput == '\0')
  848. X        return (0);
  849. X        reginput++;
  850. X        break;
  851. X    case EXACTLY:{
  852. X        register int    len;
  853. X        register char  *opnd;
  854. X
  855. X        opnd = OPERAND(scan);
  856. X        /* Inline the first character, for speed. */
  857. X        if (*opnd != *reginput)
  858. X            return (0);
  859. X        len = strlen(opnd);
  860. X        if (len > 1 && strncmp(opnd, reginput, len) != 0)
  861. X            return (0);
  862. X        reginput += len;
  863. X        }
  864. X        break;
  865. X    case ANYOF:
  866. X        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  867. X        return (0);
  868. X        reginput++;
  869. X        break;
  870. X    case ANYBUT:
  871. X        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  872. X        return (0);
  873. X        reginput++;
  874. X        break;
  875. X    case NOTHING:
  876. X        break;
  877. X    case BACK:
  878. X        break;
  879. X    case OPEN + 1:
  880. X    case OPEN + 2:
  881. X    case OPEN + 3:
  882. X    case OPEN + 4:
  883. X    case OPEN + 5:
  884. X    case OPEN + 6:
  885. X    case OPEN + 7:
  886. X    case OPEN + 8:
  887. X    case OPEN + 9:{
  888. X        register int    no;
  889. X        register char  *save;
  890. X
  891. X        no = OP(scan) - OPEN;
  892. X        save = reginput;
  893. X
  894. X        if (regmatch(nxt)) {
  895. X            /*
  896. X             * Don't set startp if some later invocation of the same
  897. X             * parentheses already has. 
  898. X             */
  899. X            if (regstartp[no] == NULL)
  900. X            regstartp[no] = save;
  901. X            return (1);
  902. X        } else
  903. X            return (0);
  904. X        }
  905. X        break;
  906. X    case CLOSE + 1:
  907. X    case CLOSE + 2:
  908. X    case CLOSE + 3:
  909. X    case CLOSE + 4:
  910. X    case CLOSE + 5:
  911. X    case CLOSE + 6:
  912. X    case CLOSE + 7:
  913. X    case CLOSE + 8:
  914. X    case CLOSE + 9:{
  915. X        register int    no;
  916. X        register char  *save;
  917. X
  918. X        no = OP(scan) - CLOSE;
  919. X        save = reginput;
  920. X
  921. X        if (regmatch(nxt)) {
  922. X            /*
  923. X             * Don't set endp if some later invocation of the same
  924. X             * parentheses already has. 
  925. X             */
  926. X            if (regendp[no] == NULL)
  927. X            regendp[no] = save;
  928. X            return (1);
  929. X        } else
  930. X            return (0);
  931. X        }
  932. X        break;
  933. X    case BRANCH:{
  934. X        register char  *save;
  935. X
  936. X        if (OP(nxt) != BRANCH)    /* No choice. */
  937. X            nxt = OPERAND(scan);    /* Avoid recursion. */
  938. X        else {
  939. X            do {
  940. X            save = reginput;
  941. X            if (regmatch(OPERAND(scan)))
  942. X                return (1);
  943. X            reginput = save;
  944. X            scan = regnext(scan);
  945. X            } while (scan != NULL && OP(scan) == BRANCH);
  946. X            return (0);
  947. X            /* NOTREACHED */
  948. X        }
  949. X        }
  950. X        break;
  951. X    case STAR:{
  952. X        register char   nextch;
  953. X        register int    no;
  954. X        register char  *save;
  955. X        register int    min;
  956. X
  957. X        /*
  958. X         * Lookahead to avoid useless match attempts when we know
  959. X         * what character comes next. 
  960. X         */
  961. X        nextch = '\0';
  962. X        if (OP(nxt) == EXACTLY)
  963. X            nextch = *OPERAND(nxt);
  964. X        min = (OP(scan) == STAR) ? 0 : 1;
  965. X        save = reginput;
  966. X        no = regrepeat(OPERAND(scan));
  967. X        while (no >= min) {
  968. X            /* If it could work, try it. */
  969. X            if (nextch == '\0' || *reginput == nextch)
  970. X            if (regmatch(nxt))
  971. X                return (1);
  972. X            /* Couldn't or didn't -- back up. */
  973. X            no--;
  974. X            reginput = save + no;
  975. X        }
  976. X        return (0);
  977. X        }
  978. X        break;
  979. X    case END:
  980. X        return (1);        /* Success! */
  981. X        break;
  982. X    default:
  983. X        regerror("memory corruption");
  984. X        return (0);
  985. X        break;
  986. X    }
  987. X
  988. X    scan = nxt;
  989. X    }
  990. X
  991. X    /*
  992. X     * We get here only if there's trouble -- normally "case END" is the
  993. X     * terminating point. 
  994. X     */
  995. X    regerror("corrupted pointers");
  996. X    return (0);
  997. X}
  998. X
  999. X/*
  1000. X - regrepeat - repeatedly match something simple, report how many
  1001. X */
  1002. X#ifdef __STDC__
  1003. X
  1004. Xstatic int regrepeat(char *p)
  1005. X
  1006. X#else
  1007. X
  1008. Xstatic int regrepeat(p)
  1009. Xchar           *p;
  1010. X
  1011. X#endif
  1012. X{
  1013. X    register int    count = 0;
  1014. X    register char  *scan;
  1015. X    register char  *opnd;
  1016. X
  1017. X    scan = reginput;
  1018. X    opnd = OPERAND(p);
  1019. X    switch (OP(p)) {
  1020. X    case ANY:
  1021. X    count = strlen(scan);
  1022. X    scan += count;
  1023. X    break;
  1024. X    case EXACTLY:
  1025. X    while (*opnd == *scan) {
  1026. X        count++;
  1027. X        scan++;
  1028. X    }
  1029. X    break;
  1030. X    case ANYOF:
  1031. X    while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1032. X        count++;
  1033. X        scan++;
  1034. X    }
  1035. X    break;
  1036. X    case ANYBUT:
  1037. X    while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1038. X        count++;
  1039. X        scan++;
  1040. X    }
  1041. X    break;
  1042. X    default:            /* Oh dear.  Called inappropriately. */
  1043. X    regerror("internal foulup");
  1044. X    count = 0;        /* Best compromise. */
  1045. X    break;
  1046. X    }
  1047. X    reginput = scan;
  1048. X
  1049. X    return (count);
  1050. X}
  1051. X
  1052. X
  1053. X/*
  1054. X - regnext - dig the "nxt" pointer out of a node
  1055. X */
  1056. X#ifdef __STDC__
  1057. X
  1058. Xstatic char *regnext(register char *p)
  1059. X
  1060. X#else
  1061. X
  1062. Xstatic char *regnext(p)
  1063. Xregister char  *p;
  1064. X
  1065. X#endif
  1066. X{
  1067. X    register int    offset;
  1068. X
  1069. X    if (p == ®dummy)
  1070. X    return (NULL);
  1071. X
  1072. X    offset = NEXT(p);
  1073. X    if (offset == 0)
  1074. X    return (NULL);
  1075. X
  1076. X    if (OP(p) == BACK)
  1077. X    return (p - offset);
  1078. X    else
  1079. X    return (p + offset);
  1080. X}
  1081. X
  1082. X#ifdef DEBUG
  1083. X
  1084. XSTATIC char    *regprop();
  1085. X
  1086. X/*
  1087. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  1088. X */
  1089. X#ifdef __STDC__
  1090. X
  1091. Xvoid regdump(regexp *r)
  1092. X
  1093. X#else
  1094. X
  1095. Xvoid regdump(r)
  1096. Xregexp         *r;
  1097. X
  1098. X#endif
  1099. X{
  1100. X    register char  *s;
  1101. X    register char   op = EXACTLY;    /* Arbitrary non-END op. */
  1102. X    register char  *nxt;
  1103. X    extern char    *strchr();
  1104. X
  1105. X
  1106. X    s = r->program + 1;
  1107. X    while (op != END) {        /* While that wasn't END last time... */
  1108. X    op = OP(s);
  1109. X    printf("%2d%s", s - r->program, regprop(s));    /* Where, what. */
  1110. X    nxt = regnext(s);
  1111. X    if (nxt == NULL)    /* nxt ptr. */
  1112. X        printf("(0)");
  1113. X    else
  1114. X        printf("(%d)", (s - r->program) + (nxt - s));
  1115. X    s += 3;
  1116. X    if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1117. X        /* Literal string, where present. */
  1118. X        while (*s != '\0') {
  1119. X        putchar(*s);
  1120. X        s++;
  1121. X        }
  1122. X        s++;
  1123. X    }
  1124. X    putchar('\n');
  1125. X    }
  1126. X
  1127. X    /* Header fields of interest. */
  1128. X    if (r->regstart != '\0')
  1129. X    printf("start `%c' ", r->regstart);
  1130. X    if (r->reganch)
  1131. X    printf("anchored ");
  1132. X    if (r->regmust != NULL)
  1133. X    printf("must have \"%s\"", r->regmust);
  1134. X    printf("\n");
  1135. X}
  1136. X
  1137. X/*
  1138. X - regprop - printable representation of opcode
  1139. X */
  1140. X#ifdef __STDC__
  1141. X
  1142. Xstatic char *regprop(char *op)
  1143. X
  1144. X#else
  1145. X
  1146. Xstatic char *regprop(op)
  1147. Xchar           *op;
  1148. X
  1149. X#endif
  1150. X{
  1151. X    register char  *p;
  1152. X    static char     buf[50];
  1153. X
  1154. X    strcpy(buf, ":");
  1155. X
  1156. X    switch (OP(op)) {
  1157. X    case BOL:
  1158. X    p = "BOL";
  1159. X    break;
  1160. X    case EOL:
  1161. X    p = "EOL";
  1162. X    break;
  1163. X    case ANY:
  1164. X    p = "ANY";
  1165. X    break;
  1166. X    case ANYOF:
  1167. X    p = "ANYOF";
  1168. X    break;
  1169. X    case ANYBUT:
  1170. X    p = "ANYBUT";
  1171. X    break;
  1172. X    case BRANCH:
  1173. X    p = "BRANCH";
  1174. X    break;
  1175. X    case EXACTLY:
  1176. X    p = "EXACTLY";
  1177. X    break;
  1178. X    case NOTHING:
  1179. X    p = "NOTHING";
  1180. X    break;
  1181. X    case BACK:
  1182. X    p = "BACK";
  1183. X    break;
  1184. X    case END:
  1185. X    p = "END";
  1186. X    break;
  1187. X    case OPEN + 1:
  1188. X    case OPEN + 2:
  1189. X    case OPEN + 3:
  1190. X    case OPEN + 4:
  1191. X    case OPEN + 5:
  1192. X    case OPEN + 6:
  1193. X    case OPEN + 7:
  1194. X    case OPEN + 8:
  1195. X    case OPEN + 9:
  1196. X    sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN);
  1197. X    p = NULL;
  1198. X    break;
  1199. X    case CLOSE + 1:
  1200. X    case CLOSE + 2:
  1201. X    case CLOSE + 3:
  1202. X    case CLOSE + 4:
  1203. X    case CLOSE + 5:
  1204. X    case CLOSE + 6:
  1205. X    case CLOSE + 7:
  1206. X    case CLOSE + 8:
  1207. X    case CLOSE + 9:
  1208. X    sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE);
  1209. X    p = NULL;
  1210. X    break;
  1211. X    case STAR:
  1212. X    p = "STAR";
  1213. X    break;
  1214. X    default:
  1215. X    regerror("corrupted opcode");
  1216. X    break;
  1217. X    }
  1218. X    if (p != NULL)
  1219. X    strcat(buf, p);
  1220. X    return (buf);
  1221. X}
  1222. X#endif
  1223. X
  1224. X/*
  1225. X * The following is provided for those people who do not have strcspn() in
  1226. X * their C libraries.  They should get off their butts and do something
  1227. X * about it; at least one public-domain implementation of those (highly
  1228. X * useful) string routines has been published on Usenet.
  1229. X */
  1230. X#ifdef STRCSPN
  1231. X/*
  1232. X * strcspn - find length of initial segment of s1 consisting entirely
  1233. X * of characters not from s2
  1234. X */
  1235. X
  1236. X#ifdef __STDC__
  1237. X
  1238. Xstatic int strcspn(char *s1, char *s2)
  1239. X
  1240. X#else
  1241. X
  1242. Xstatic int strcspn(s1, s2)
  1243. Xchar           *s1;
  1244. Xchar           *s2;
  1245. X
  1246. X#endif
  1247. X{
  1248. X    register char  *scan1;
  1249. X    register char  *scan2;
  1250. X    register int    count;
  1251. X
  1252. X    count = 0;
  1253. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1254. X    for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  1255. X        if (*scan1 == *scan2++)
  1256. X        return (count);
  1257. X    count++;
  1258. X    }
  1259. X    return (count);
  1260. X}
  1261. X#endif
  1262. X
  1263. X
  1264. X/*
  1265. X - regsub - perform substitutions after a regexp match
  1266. X */
  1267. X#ifdef __STDC__
  1268. X
  1269. Xvoid regsub(regexp *prog, char *source, char *dest)
  1270. X
  1271. X#else
  1272. X
  1273. Xvoid regsub(prog, source, dest)
  1274. Xregexp         *prog;
  1275. Xchar           *source;
  1276. Xchar           *dest;
  1277. X
  1278. X#endif
  1279. X{
  1280. X    register char  *src;
  1281. X    register char  *dst;
  1282. X    register char   c;
  1283. X    register int    no;
  1284. X    register int    len;
  1285. X    extern char    *strncpy();
  1286. X
  1287. X    if (prog == NULL || source == NULL || dest == NULL) {
  1288. X    regerror("NULL parm to regsub");
  1289. X    return;
  1290. X    }
  1291. X    if (UCHARAT(prog->program) != MAGIC) {
  1292. X    regerror("damaged regexp fed to regsub");
  1293. X    return;
  1294. X    }
  1295. X    src = source;
  1296. X    dst = dest;
  1297. X    while ((c = *src++) != '\0') {
  1298. X    if (c == '&')
  1299. X        no = 0;
  1300. X    else if (c == '\\' && '0' <= *src && *src <= '9')
  1301. X        no = *src++ - '0';
  1302. X    else
  1303. X        no = -1;
  1304. X
  1305. X    if (no < 0) {        /* Ordinary character. */
  1306. X        if (c == '\\' && (*src == '\\' || *src == '&'))
  1307. X        c = *src++;
  1308. X        *dst++ = c;
  1309. X    } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
  1310. X        len = prog->endp[no] - prog->startp[no];
  1311. X        strncpy(dst, prog->startp[no], len);
  1312. X        dst += len;
  1313. X        if (len != 0 && *(dst - 1) == '\0') {    /* strncpy hit NUL. */
  1314. X        regerror("damaged match string");
  1315. X        return;
  1316. X        }
  1317. X    }
  1318. X    }
  1319. X    *dst++ = '\0';
  1320. X}
  1321. X
  1322. X
  1323. X#ifdef __STDC__
  1324. X
  1325. Xvoid regerror(char *s)
  1326. X
  1327. X#else
  1328. X
  1329. Xvoid regerror(s)
  1330. Xchar           *s;
  1331. X
  1332. X#endif
  1333. X{
  1334. X    fprintf(stderr, "regexp(3): %s", s);
  1335. X    exit(1);
  1336. X}
  1337. END_OF_regexp.c
  1338. if test 30611 -ne `wc -c <regexp.c`; then
  1339.     echo shar: \"regexp.c\" unpacked with wrong size!
  1340. fi
  1341. # end of overwriting check
  1342. fi
  1343. echo shar: End of archive 6 \(of 6\).
  1344. cp /dev/null ark6isdone
  1345. MISSING=""
  1346. for I in 1 2 3 4 5 6 ; do
  1347.     if test ! -f ark${I}isdone ; then
  1348.     MISSING="${MISSING} ${I}"
  1349.     fi
  1350. done
  1351. if test "${MISSING}" = "" ; then
  1352.     echo You have unpacked all 6 archives.
  1353.     rm -f ark[1-9]isdone
  1354. else
  1355.     echo You still need to unpack the following archives:
  1356.     echo "        " ${MISSING}
  1357. fi
  1358. ##  End of shell archive.
  1359. exit 0
  1360.